//
//  SocketParsable.m
//  Socket.IO-Client
//
//  Created by alanwang.dev on 16/8/8.
//  Copyright © 2016年 com.alanwang.dev. All rights reserved.
//

#import "SocketParsable.h"
#import "SocketStringReader.h"
#import "NSString+String.h"

@interface SocketParsable ()

@end

@implementation SocketParsable

#pragma mark public

- (void) parseSocketMessage:(NSString *)message {
  if (message.length <= 0) {
    return;
  }
  Either *result = [self parseString: message];
  if (result.Left) {
    
  }
  if (result.Right) {
    [self handlePacket:result.Right];
  }
}

- (void) parseBinaryData:(NSData *)data {
  if (self.waitingPackets.count == 0) {
    return;
  }
  SocketPacket *packet = self.waitingPackets.lastObject;
  [packet addData:data];
  [self.waitingPackets removeLastObject];
  if (packet.type != BinaryAck) {
    [self handleEvent:packet.event data:packet.args?:@[] isInternalMessage:NO ack:packet.id];
  } else {
    [self handleAck:packet.id data:packet.args];
  }
}

- (Either *)parseString:(NSString *)message {
  SocketStringReader *parser = [[SocketStringReader alloc] initWithMessage:message];
  NSInteger packetType = [[parser read:1] integerValue];
  if (packetType == 0 && !(packetType == 0)) {
    packetType = -1;
  }
  if (packetType > 6 || packetType < 0) {
    Either *re = [[Either alloc] init];
    re.Left = @"Invalid packet type";
    return re;
  }
  if (![parser hasNext]) {
    Either *re = [[Either alloc] init];
    re.Right = [[SocketPacket alloc] initWithType:(PacketType)packetType nsp:@"/"];
    return re;
  }
  NSString *namespace = @"/";
  NSInteger placeholders = -1;
  if (packetType == BinaryEvent || packetType == BinaryAck) {
    NSInteger holders = [[parser readUntilStringOccurence:@"-"] integerValue];
    NSInteger length = [[parser readUntilStringOccurence:@"-"] length];
    NSMutableString *str = [NSMutableString string];
    for (int i = 0; i < length; i++) {
      [str appendString:@"0"];
    }
    if (holders == 0 && ![[parser readUntilStringOccurence:@"-"] isEqualToString:str]) {
      holders = -1;
    }
    if (holders <0 || holders > 6) {
      Either *re = [Either new];
      re.Left = @"Invalid packet";
      return re;
    } else {
      placeholders = holders;
    }
  }
  if ([[parser currentCharacter] isEqualToString:@"/"]) {
    namespace = [parser readUntilStringOccurence:@","]?:[parser readUntilEnd];
  }
  
  if (![parser hasNext]) {
    Either *re = [Either new];
    re.Right = [[SocketPacket alloc] initWithType:(PacketType)packetType data:nil id:0 nsp:namespace placeholders:placeholders binary:nil];
    return re;
  }
  
  NSString *idString = @"";
  
  if (packetType == Error) {
    [parser advanceIndexBy:-1];
  }
  while ([parser hasNext] && packetType != Error) {
    NSInteger intd = [[parser read:1] convert2Int];
    
//    if (intd == 0 && (intd != 0)) {
//      intd = -1;
//    }
    if (intd >= 0) {
      idString  = [idString stringByAppendingString:@(intd).description];
    } else {
      [parser advanceIndexBy:-2];
      break;
    }
  }
  NSString *d = [message substringFromIndex:parser.currentIndex+1];
  //可能有问题
  id dataResult = [self parseData:d];
  if ([dataResult isKindOfClass:[NSString class]]) {
    Either *re = [Either new];
    re.Left = dataResult;
    return re;
  } else  {
    Either *re = [Either new];
    re.Right = [[SocketPacket alloc] initWithType:(PacketType)packetType data:dataResult id:[idString intValue] nsp:namespace placeholders:placeholders binary:nil];
    return re;
  }
}

#pragma mark private
- (BOOL)isCorrectNamespace:(NSString *)nsp{
  return ([self.nsp isEqualToString:nsp]);
}

- (void)handleConnect:(SocketPacket *)p{
  if ([p.nsp isEqualToString:@"/"] && ![self.nsp isEqualToString:@"/"]) {
    [self joinNamespace:self.nsp];
  }else{
    [self didConnect];
  }
}

- (void)handlePacket:(SocketPacket *)pack{
  if (pack.type == Event && [self isCorrectNamespace:pack.nsp]) {
    [self handleEvent:pack.event data:pack.args isInternalMessage:NO ack:pack.id];
  } else if (pack.type == Ack && [self isCorrectNamespace:pack.nsp]) {
    [self handleAck:pack.id data:pack.data];
  } else if (pack.type == BinaryEvent && [self isCorrectNamespace:pack.nsp]) {
    [self.waitingPackets addObject: pack];
  } else if (pack.type == BinaryAck && [self isCorrectNamespace:pack.nsp]) {
    [self.waitingPackets addObject:pack];
  } else if (pack.type == Connect) {
    [self handleConnect:pack];
  } else if (pack.type == Disconnect) {
    [self didDisconnect:@"Got Disconnect"];
  } else if (pack.type == Error) {
    [self handleEvent:@"error" data:pack.data isInternalMessage:YES ack:pack.id];
  } else {
    
  }
}

- (id)parseData:(NSString *)data {
  NSData *stringData = [data dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO];
  NSError *error;
  id result = [NSJSONSerialization JSONObjectWithData:stringData options:NSJSONReadingMutableContainers error:&error];
  if (error) {
    return @"Error parsing data for packet";
  } else {
    if ([result isKindOfClass:[NSArray class]]) {
      return result;
    } else {
      return @"Expected data array";
    }
  }
}


@end
